package com.atguigu.daijia.driver.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.atguigu.daijia.common.constant.SystemConstant;
import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.driver.config.TencentCloudProperties;
import com.atguigu.daijia.driver.mapper.*;
import com.atguigu.daijia.driver.service.CosService;
import com.atguigu.daijia.driver.service.DriverInfoService;
import com.atguigu.daijia.model.entity.driver.*;
import com.atguigu.daijia.model.form.driver.DriverFaceModelForm;
import com.atguigu.daijia.model.form.driver.UpdateDriverAuthInfoForm;
import com.atguigu.daijia.model.vo.driver.DriverAuthInfoVo;
import com.atguigu.daijia.model.vo.driver.DriverInfoVo;
import com.atguigu.daijia.model.vo.driver.DriverLoginVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tencentcloudapi.common.AbstractModel;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.iai.v20200303.IaiClient;
import com.tencentcloudapi.iai.v20200303.models.*;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;

/**
 * @author 谢忠涵7
 */
@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class DriverInfoServiceImpl extends ServiceImpl<DriverInfoMapper, DriverInfo> implements DriverInfoService {

    @Autowired
    private  WxMaService wxService;
    @Autowired
    private DriverInfoMapper driverInfoMapper;
    @Autowired
    private DriverSetMapper driverSetMapper;
    @Autowired
    private DriverAccountMapper driverAccountMapper;
    @Autowired
    private DriverLoginLogMapper driverLoginLogMapper;
    @Autowired
    private CosService cosService;
    @Autowired
    private TencentCloudProperties tencentCloudProperties;
    @Autowired
    private DriverFaceRecognitionMapper driverFaceRecognitionMapper;
    //司机微信小程序登录
    @Override
    public Long login(String code) {
       //1.根据code + appid + 密钥 通过微信接口生成 openid
        try {
            WxMaJscode2SessionResult sessionInfo = wxService
                    .getUserService().getSessionInfo(code);
            String openid = sessionInfo.getOpenid();
            // 2.通过openid 查询数据库
            LambdaQueryWrapper<DriverInfo> queryWrapper =
                    new LambdaQueryWrapper<>();
            queryWrapper.eq(DriverInfo::getWxOpenId,openid);
            DriverInfo driverInfo = driverInfoMapper.selectOne(queryWrapper);
            //3.如果没有数据 说明是第一次登录
            if(null == driverInfo){
                //4.初始化信息
                //5.插入 司机信息
                driverInfo = new DriverInfo();
                driverInfo.setNickname(String.valueOf(System.currentTimeMillis()));
                driverInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
                driverInfo.setWxOpenId(openid);
                this.save(driverInfo);
                //6.插入 司机基本设置信息
                DriverSet driverSet = new DriverSet();
                driverSet.setDriverId(driverInfo.getId());
                //0：无限制
                driverSet.setOrderDistance(new BigDecimal(0));
                //默认接单范围：5公里
                driverSet.setAcceptDistance(new BigDecimal(SystemConstant.ACCEPT_DISTANCE));
                //0：否 1：是 是否自动接单
                driverSet.setIsAutoAccept(0);
                driverSetMapper.insert(driverSet);
                //7.插入 司机账户信息
                DriverAccount driverAccount = new DriverAccount();
                driverAccount.setDriverId(driverInfo.getId());
                driverAccountMapper.insert(driverAccount);
            }
            //8.插入 司机登录信息
            DriverLoginLog driverLoginLog = new DriverLoginLog();
            driverLoginLog.setDriverId(driverInfo.getId());
            driverLoginLog.setMsg("小程序登录");
            driverLoginLogMapper.insert(driverLoginLog);
            //9.无论是否为第一次登录都返回 司机id
            return driverInfo.getId();
        } catch (WxErrorException e) {
            log.warn("司机登录: code {}",code);
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
    }

    /**
     *  获取司机登录信息
     */
    @Override
    public DriverLoginVo getDriverLoginInfo(Long driverId) {
        //1.查询数据库
        DriverInfo driverInfo = driverInfoMapper.selectById(driverId);
        DriverLoginVo driverLoginVo = new DriverLoginVo();
        //2.封装VO对象
        BeanUtils.copyProperties(driverInfo,driverLoginVo);
        boolean isArchiveFace = StringUtils.hasText( driverInfo.getFaceModelId());
        driverLoginVo.setIsArchiveFace(isArchiveFace);
        //返回
        return driverLoginVo;
    }

    /**
     * 获取司机认证信息
     */
    @Override
    public DriverAuthInfoVo getDriverAuthInfo(Long driverId) {
        DriverInfo driverInfo = driverInfoMapper.selectById(driverId);
        DriverAuthInfoVo driverAuthInfoVo = new DriverAuthInfoVo();
        BeanUtils.copyProperties(driverInfo,driverAuthInfoVo);
        driverAuthInfoVo.setIdcardBackShowUrl(cosService.getEchoPath(driverAuthInfoVo
                                                            .getIdcardBackUrl()));
        driverAuthInfoVo.setIdcardFrontShowUrl(cosService.getEchoPath(driverAuthInfoVo
                .getIdcardFrontUrl()));
        driverAuthInfoVo.setIdcardHandShowUrl(cosService.getEchoPath(driverAuthInfoVo
                .getIdcardHandUrl()));
        driverAuthInfoVo.setDriverLicenseFrontShowUrl(cosService.getEchoPath(driverAuthInfoVo
                .getDriverLicenseFrontUrl()));
        driverAuthInfoVo.setDriverLicenseBackShowUrl(cosService.getEchoPath(driverAuthInfoVo
                .getDriverLicenseBackUrl()));
        driverAuthInfoVo.setDriverLicenseHandShowUrl(cosService.getEchoPath(driverAuthInfoVo
                .getDriverLicenseHandUrl()));
        return driverAuthInfoVo;
    }

    /**
     * 更新司机认证信息
     */
    @Override
    public Boolean updateDriverAuthInfo(UpdateDriverAuthInfoForm updateDriverAuthInfoForm) {
        DriverInfo updateDriverInfo = new DriverInfo();
        updateDriverInfo.setId(updateDriverAuthInfoForm.getDriverId());
        BeanUtils.copyProperties(updateDriverAuthInfoForm,updateDriverInfo);
        return this.updateById(updateDriverInfo);
    }

    /**
     * 创建司机人脸识别模型
     */
    @Override
    public Boolean creatDriverFaceModel(DriverFaceModelForm driverFaceModelForm) {
        DriverInfo driverInfo = this.getById(driverFaceModelForm.getDriverId());
        try {
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential cred = new Credential(tencentCloudProperties.getSecretId(), tencentCloudProperties.getSecretKey());
            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("iai.tencentcloudapi.com");
            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            // 实例化要请求产品的client对象,clientProfile是可选的
            IaiClient client = new IaiClient(cred, tencentCloudProperties.getRegion(), clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            CreatePersonRequest req = new CreatePersonRequest();
            req.setGroupId(tencentCloudProperties.getPersionGroupId());
            //基本信息
            req.setPersonId(String.valueOf(driverInfo.getId()));
            req.setGender(Long.parseLong(driverInfo.getGender()));
            req.setQualityControl(4L);
            req.setUniquePersonControl(4L);
            req.setPersonName(driverInfo.getName());
            req.setImage(driverFaceModelForm.getImageBase64());
            // 返回的resp是一个CreatePersonResponse的实例，与请求对象对应
            CreatePersonResponse resp = client.CreatePerson(req);
            // 输出json格式的字符串回包
            System.out.println(CreatePersonResponse.toJsonString(resp));
            if (StringUtils.hasText(resp.getFaceId())) {
                //人脸校验必要参数，保存到数据库表
                driverInfo.setFaceModelId(resp.getFaceId());
                this.updateById(driverInfo);
            }

        } catch (TencentCloudSDKException e) {
            System.out.println(e.toString());
            return false;
        }
        return true;
    }

    /**
     * @description: 根据司机id获取司机设置信息
     * @author: xiaoxie
     * @date: 2024/10/26 23:03
     * @param: [driverId] 司机id
     * @return: DriverSet 对象
     **/
    @Override
    public DriverSet getDriverSet(Long driverId) {
        LambdaQueryWrapper<DriverSet> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DriverSet::getDriverId, driverId);
        return driverSetMapper.selectOne(queryWrapper);
    }

    /**
     * @description: 查询是否进行过人脸识别
     * @author: xiaoxie
     * @date: 2024/10/28 10:40
     * @param: [driverId] 司机id
     * @return:
     **/
    @Override
    public Boolean isFaceRecognition(Long driverId) {
        //1. 通过查询数据库 条件为 司机id 和 日期 (和当前日期为同一天)
        LambdaQueryWrapper<DriverFaceRecognition> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DriverFaceRecognition::getDriverId, driverId);
        wrapper.eq(DriverFaceRecognition::getFaceDate
                 , new DateTime().toString("yyyy-MM-dd"));
        Long count = driverFaceRecognitionMapper.selectCount(wrapper);
        return count > 0;
    }

    /**
     * @description: 通过腾讯云验证司机人脸是否正确
     * @author: xiaoxie
     * @date: 2024/10/28 10:48
     * @param: [driverFaceModelForm] 前端图片
     * @return: java.lang.Boolean
     **/
    @Override
    public Boolean verifyDriverFace(DriverFaceModelForm driverFaceModelForm) {
        try {
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential cred = new Credential(tencentCloudProperties.getSecretId()
                                           , tencentCloudProperties.getSecretKey());
            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("iai.tencentcloudapi.com");
            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            // 实例化要请求产品的client对象,clientProfile是可选的
            IaiClient client = new IaiClient(cred, tencentCloudProperties.getRegion()
                                           , clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            VerifyFaceRequest req = new VerifyFaceRequest();
            req.setImage(driverFaceModelForm.getImageBase64());
            req.setPersonId(String.valueOf(driverFaceModelForm.getDriverId()));
            // 返回的resp是一个VerifyFaceResponse的实例，与请求对象对应
            VerifyFaceResponse resp = client.VerifyFace(req);
            if(resp.getIsMatch()) {
                if(this.detectLiveFace(driverFaceModelForm.getImageBase64())) {
                    //插入数据库
                    DriverFaceRecognition driverFaceRecognition = new DriverFaceRecognition();
                    driverFaceRecognition.setDriverId(driverFaceModelForm.getDriverId());
                    driverFaceRecognition.setFaceDate(new Date());
                    driverFaceRecognitionMapper.insert(driverFaceRecognition);
                    return true;
                }
            }

        }catch (Exception e){
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
        throw new GuiguException(ResultCodeEnum.FACE_FAIL);
    }

    /**
     * @description: 更新司机接单状态
     * @author: xiaoxie
     * @date: 2024/10/28 10:59
     * @param: [driverId, status]
     * @return: java.lang.Boolean
     **/
    @Override
    public Boolean updateServiceStatus(Long driverId, Integer status) {
        DriverSet driverSet = new DriverSet();
        driverSet.setServiceStatus(status);
        LambdaUpdateWrapper<DriverSet> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(DriverSet::getDriverId, driverId);
        driverSetMapper.update(driverSet,wrapper);
        return true;
    }

    /**
     * 获取司机信息
     */
    @Override
    public DriverInfoVo getDriverInfo(Long driverId) {
        LambdaQueryWrapper<DriverInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DriverInfo::getId, driverId);
        DriverInfo driverInfo = driverInfoMapper.selectOne(wrapper);
        DriverInfoVo driverInfoVo = new DriverInfoVo();
        BeanUtils.copyProperties(driverInfo,driverInfoVo);
        //驾龄设置
        int currentYear = new DateTime(new Date()).getYear();
        int firstYear = new DateTime(driverInfo.getDriverLicenseIssueDate()).getYear();
        driverInfoVo.setDriverLicenseAge(currentYear-firstYear);
        return driverInfoVo;
    }

    /**
     * 获取司机OpenId
     */
    @Override
    public String getDriverOpenId(Long driverId) {
        LambdaQueryWrapper<DriverInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DriverInfo::getId, driverId);
        DriverInfo driverInfo = driverInfoMapper.selectOne(wrapper);
        if(driverInfo == null) {
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
        return driverInfo.getWxOpenId();
    }

    /**
     * 人脸静态活体检测
     * 文档地址：
     * <a href="https://cloud.tencent.com/document/api/867/48501">...</a>
     * <a href="https://console.cloud.tencent.com/api/explorer?Product=iai&Version=2020-03-03&Action=DetectLiveFace">...</a>
     * @param imageBase64
     * @return
     */
    private Boolean detectLiveFace(String imageBase64) {
        try {
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性。以下代码示例仅供参考，建议采用更安全的方式来使用密钥，请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential cred = new Credential(tencentCloudProperties.getSecretId(), tencentCloudProperties.getSecretKey());
            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("iai.tencentcloudapi.com");
            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            // 实例化要请求产品的client对象,clientProfile是可选的
            IaiClient client = new IaiClient(cred, tencentCloudProperties.getRegion(), clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DetectLiveFaceRequest req = new DetectLiveFaceRequest();
            req.setImage(imageBase64);
            // 返回的resp是一个DetectLiveFaceResponse的实例，与请求对象对应
            DetectLiveFaceResponse resp = client.DetectLiveFace(req);
            // 输出json格式的字符串回包
            System.out.println(DetectLiveFaceResponse.toJsonString(resp));
            if (resp.getIsLiveness()) {
                return true;
            }
        } catch (TencentCloudSDKException e) {
            System.out.println(e.toString());
        }
        return false;
    }

}